winsafe\kernel\handles/
hfile.rs

1#![allow(non_camel_case_types, non_snake_case)]
2
3use crate::co;
4use crate::decl::*;
5use crate::guard::*;
6use crate::kernel::{ffi, privs::*};
7use crate::prelude::*;
8
9handle! { HFILE;
10	/// Handle to a
11	/// [file](https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types#hfile).
12	/// Originally just a `HANDLE`.
13	///
14	/// Unless you need something specific, consider using the
15	/// [`File`](crate::File) high-level abstraction.
16}
17
18impl HFILE {
19	/// [`CreateFile`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew)
20	/// function.
21	///
22	/// The error code is also returned because it can carry information even if
23	/// the file is successfully open.
24	///
25	/// Unless you need something specific, consider using the
26	/// [`File`](crate::File) high-level abstraction.
27	///
28	/// # Examples
29	///
30	/// Opening an existing file as read-only:
31	///
32	/// ```no_run
33	/// use winsafe::{self as w, prelude::*, co};
34	///
35	/// let (hfile, status) = w::HFILE::CreateFile(
36	///     "C:\\Temp\\test.txt",
37	///     co::GENERIC::READ,
38	///     Some(co::FILE_SHARE::READ),
39	///     None,
40	///     co::DISPOSITION::OPEN_EXISTING,
41	///     co::FILE_ATTRIBUTE::NORMAL,
42	///     None,
43	///     None,
44	///     None,
45	/// )?;
46	/// # w::SysResult::Ok(())
47	/// ```
48	///
49	/// Opening a file for read and write. If the file doesn't exist, create it:
50	///
51	/// ```no_run
52	/// use winsafe::{self as w, prelude::*, co};
53	///
54	/// let (hfile, status) = w::HFILE::CreateFile(
55	///     "C:\\Temp\\test.txt",
56	///     co::GENERIC::READ | co::GENERIC::WRITE,
57	///     None,
58	///     None,
59	///     co::DISPOSITION::OPEN_ALWAYS,
60	///     co::FILE_ATTRIBUTE::NORMAL,
61	///     None,
62	///     None,
63	///     None,
64	/// )?;
65	/// # w::SysResult::Ok(())
66	/// ```
67	#[must_use]
68	pub fn CreateFile(
69		file_name: &str,
70		desired_access: co::GENERIC,
71		share_mode: Option<co::FILE_SHARE>,
72		security_attributes: Option<&SECURITY_ATTRIBUTES>,
73		creation_disposition: co::DISPOSITION,
74		attributes: co::FILE_ATTRIBUTE,
75		flags: Option<co::FILE_FLAG>,
76		security: Option<co::FILE_SECURITY>,
77		hfile_template: Option<&HFILE>,
78	) -> SysResult<(CloseHandleGuard<HFILE>, co::ERROR)> {
79		unsafe {
80			match HFILE(ffi::CreateFileW(
81				WString::from_str(file_name).as_ptr(),
82				desired_access.raw(),
83				share_mode.unwrap_or_default().raw(),
84				pcvoid_or_null(security_attributes),
85				creation_disposition.raw(),
86				attributes.raw()
87					| flags.unwrap_or_default().raw()
88					| security.map_or(0, |s| SECURITY_SQOS_PRESENT | s.raw()),
89				hfile_template.map_or(std::ptr::null_mut(), |h| h.ptr()),
90			) as _)
91			{
92				HFILE::NULL | HFILE::INVALID => Err(GetLastError()),
93				handle => Ok((CloseHandleGuard::new(handle), GetLastError())),
94			}
95		}
96	}
97
98	/// [`CreateFileMapping`](https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-createfilemappingw)
99	/// function.
100	///
101	/// Unless you need something specific, consider using the
102	/// [`FileMapped`](crate::FileMapped) high-level abstraction.
103	#[must_use]
104	pub fn CreateFileMapping(
105		&self,
106		mapping_attrs: Option<&SECURITY_ATTRIBUTES>,
107		protect: co::PAGE,
108		sec: Option<co::SEC>,
109		max_size: Option<u64>,
110		mapping_name: Option<&str>,
111	) -> SysResult<CloseHandleGuard<HFILEMAP>> {
112		unsafe {
113			ptr_to_sysresult_handle(ffi::CreateFileMappingFromApp(
114				self.ptr(),
115				pcvoid_or_null(mapping_attrs),
116				protect.raw() | sec.map_or(0, |f| f.raw()),
117				max_size.unwrap_or_default(),
118				WString::from_opt_str(mapping_name).as_ptr(),
119			))
120			.map(|h| CloseHandleGuard::new(h))
121		}
122	}
123
124	/// [`GetFileInformationByHandle`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandle)
125	/// function.
126	pub fn GetFileInformationByHandle(&self) -> SysResult<BY_HANDLE_FILE_INFORMATION> {
127		let mut fi = BY_HANDLE_FILE_INFORMATION::default();
128		bool_to_sysresult(unsafe { ffi::GetFileInformationByHandle(self.ptr(), pvoid(&mut fi)) })
129			.map(|_| fi)
130	}
131
132	/// [`GetFileSizeEx`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfilesizeex)
133	/// function.
134	#[must_use]
135	pub fn GetFileSizeEx(&self) -> SysResult<u64> {
136		let mut sz_buf = 0i64;
137		bool_to_sysresult(unsafe { ffi::GetFileSizeEx(self.ptr(), &mut sz_buf) })
138			.map(|_| sz_buf as _)
139	}
140
141	/// [`GetFileTime`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfiletime)
142	/// function.
143	///
144	/// Returns, respectively:
145	/// 1. creation time;
146	/// 2. last access time;
147	/// 3. last write time.
148	///
149	/// # Examples
150	///
151	/// ```no_run
152	/// use winsafe::{self as w, prelude::*, co};
153	///
154	/// let hfile: w::HFILE; // initialized somewhere
155	/// # let hfile = w::HFILE::NULL;
156	///
157	/// let (creation, last_access, last_write) = hfile.GetFileTime()?;
158	/// # w::SysResult::Ok(())
159	/// ```
160	pub fn GetFileTime(&self) -> SysResult<(FILETIME, FILETIME, FILETIME)> {
161		let (mut creation, mut last_access, mut last_write) =
162			(FILETIME::default(), FILETIME::default(), FILETIME::default());
163
164		bool_to_sysresult(unsafe {
165			ffi::GetFileTime(
166				self.ptr(),
167				pvoid(&mut creation),
168				pvoid(&mut last_access),
169				pvoid(&mut last_write),
170			)
171		})
172		.map(|_| (creation, last_access, last_write))
173	}
174
175	/// [`GetFileType`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfiletype)
176	/// function.
177	#[must_use]
178	pub fn GetFileType(&self) -> SysResult<co::FILE_TYPE> {
179		match unsafe { co::FILE_TYPE::from_raw(ffi::GetFileType(self.ptr())) } {
180			co::FILE_TYPE::UNKNOWN => match GetLastError() {
181				co::ERROR::SUCCESS => Ok(co::FILE_TYPE::UNKNOWN), // actual unknown type
182				err => Err(err),
183			},
184			ty => Ok(ty),
185		}
186	}
187
188	/// [`LockFile`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-lockfile)
189	/// function.
190	///
191	/// In the original C implementation, you must call
192	/// [`UnlockFile`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-unlockfile)
193	/// as a cleanup operation.
194	///
195	/// Here, the cleanup is performed automatically, because `LockFile` returns
196	/// an [`UnlockFileGuard`](crate::guard::UnlockFileGuard), which
197	/// automatically calls `UnlockFile` when the guard goes out of scope. You
198	/// must, however, keep the guard alive, otherwise the cleanup will be
199	/// performed right away.
200	///
201	/// # Examples
202	///
203	/// ```no_run
204	/// use winsafe::{self as w, prelude::*};
205	///
206	/// let hfile: w::HFILE; // initialized somewhere
207	/// # let hfile = w::HFILE::NULL;
208	///
209	/// let total_size = hfile.GetFileSizeEx()?;
210	///
211	/// let _lock_guard = hfile.LockFile(0, total_size as _)?; // keep guard alive
212	///
213	/// // file read/write operations...
214	///
215	/// // UnlockFile() called automatically
216	/// # w::SysResult::Ok(())
217	/// ```
218	#[must_use]
219	pub fn LockFile(&self, offset: u64, num_bytes_to_lock: u64) -> SysResult<UnlockFileGuard<'_>> {
220		unsafe {
221			bool_to_sysresult(ffi::LockFile(
222				self.ptr(),
223				LODWORD(offset),
224				HIDWORD(offset),
225				LODWORD(num_bytes_to_lock),
226				HIDWORD(num_bytes_to_lock),
227			))
228			.map(|_| UnlockFileGuard::new(self, offset, num_bytes_to_lock))
229		}
230	}
231
232	/// [`ReadFile`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile)
233	/// function.
234	///
235	/// Reads at most `buffer.len()` bytes from the file, starting at the
236	/// current file pointer offset. Returns how many bytes were actually read.
237	/// The file pointer is then incremented by the number of bytes read.
238	///
239	/// Note that asynchronous reading – which use the
240	/// [`OVERLAPPED`](crate::OVERLAPPED) struct – is not currently supported by
241	/// this method, because the buffer must remain untouched until the async
242	/// operation is complete, thus making the method unsound.
243	pub fn ReadFile(&self, buffer: &mut [u8]) -> SysResult<u32> {
244		let mut bytes_read = 0u32;
245		bool_to_sysresult(unsafe {
246			ffi::ReadFile(
247				self.ptr(),
248				buffer.as_mut_ptr() as _,
249				buffer.len() as _,
250				&mut bytes_read,
251				std::ptr::null_mut(),
252			)
253		})
254		.map(|_| bytes_read)
255	}
256
257	/// [`SetEndOfFile`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setendoffile)
258	/// function.
259	pub fn SetEndOfFile(&self) -> SysResult<()> {
260		bool_to_sysresult(unsafe { ffi::SetEndOfFile(self.ptr()) })
261	}
262
263	/// [`SetFilePointerEx`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfilepointerex)
264	/// function.
265	pub fn SetFilePointerEx(
266		&self,
267		distance_to_move: i64,
268		move_method: co::FILE_STARTING_POINT,
269	) -> SysResult<i64> {
270		let mut new_offset = 0i64;
271
272		bool_to_sysresult(unsafe {
273			ffi::SetFilePointerEx(self.ptr(), distance_to_move, &mut new_offset, move_method.raw())
274		})
275		.map(|_| new_offset)
276	}
277
278	/// [`SetFileTime`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfiletime)
279	/// function.
280	pub fn SetFileTime(
281		&self,
282		creation_time: Option<&FILETIME>,
283		last_access_time: Option<&FILETIME>,
284		last_write_time: Option<&FILETIME>,
285	) -> SysResult<()> {
286		bool_to_sysresult(unsafe {
287			ffi::SetFileTime(
288				self.ptr(),
289				pcvoid_or_null(creation_time),
290				pcvoid_or_null(last_access_time),
291				pcvoid_or_null(last_write_time),
292			)
293		})
294	}
295
296	/// [`WriteFile`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefile)
297	/// function.
298	///
299	/// Returns the number of bytes written.
300	///
301	/// Note that asynchronous writing – which use the
302	/// [`OVERLAPPED`](crate::OVERLAPPED) struct – is not currently supported by
303	/// this method, because the buffer must remain untouched until the async
304	/// operation is complete, thus making the method unsound.
305	pub fn WriteFile(&self, data: &[u8]) -> SysResult<u32> {
306		let mut bytes_written = 0u32;
307		bool_to_sysresult(unsafe {
308			ffi::WriteFile(
309				self.ptr(),
310				vec_ptr(data) as _,
311				data.len() as _,
312				&mut bytes_written,
313				std::ptr::null_mut(),
314			)
315		})
316		.map(|_| bytes_written)
317	}
318}